package com.iotmonitor.iot.service.impl;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.iotmonitor.iot.mapper.TdEngineMapper;
import com.iotmonitor.iot.service.ITbQuotaService;
import com.iotmonitor.iot.domain.TbQuota;
import com.iotmonitor.iot.domain.dto.DeviceDTO;
import com.iotmonitor.iot.domain.dto.DeviceInfoDTO;
import com.iotmonitor.iot.domain.dto.QuotaDTO;
import com.iotmonitor.iot.domain.dto.QuotaInfo;
import com.iotmonitor.iot.mapper.TbQuotaMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;


/**
 * 指标配置Service业务层处理
 *
 * @author ruoyi
 * @date 2023-08-11
 */
@Service
public class TbQuotaServiceImpl implements ITbQuotaService {
    @Autowired
    private TbQuotaMapper tbQuotaMapper;

    @Autowired
    private TdEngineMapper tdEngineMapper;

    /**
     * 数据库名称
     */
    @Value("${spring.datasource.dynamic.datasource.slave.dbName:thinglinks}")
    private String dataBaseName;

    /**
     * 查询指标配置
     *
     * @param id 指标配置主键
     * @return 指标配置
     */
    @Override
    public TbQuota selectTbQuotaById(Long id) {
        return tbQuotaMapper.selectTbQuotaById(id);
    }

    /**
     * 查询指标配置列表
     *
     * @param tbQuota 指标配置
     * @return 指标配置
     */
    @Override
    public List<TbQuota> selectTbQuotaList(TbQuota tbQuota) {
        return tbQuotaMapper.selectTbQuotaList(tbQuota);
    }

    @Override
    public List<TbQuota> queryNumberQuota(TbQuota tbQuota) {
        List<TbQuota> list = tbQuotaMapper.queryNumberQuota(tbQuota);
        return list;
    }

    /**
     * 新增指标配置
     *
     * @param tbQuota 指标配置
     * @return 结果
     */
    @Override
    public int insertTbQuota(TbQuota tbQuota) {
        return tbQuotaMapper.insertTbQuota(tbQuota);
    }

    /**
     * 修改指标配置
     *
     * @param tbQuota 指标配置
     * @return 结果
     */
    @Override
    public int updateTbQuota(TbQuota tbQuota) {
        return tbQuotaMapper.updateTbQuota(tbQuota);
    }

    /**
     * 批量删除指标配置
     *
     * @param ids 需要删除的指标配置主键
     * @return 结果
     */
    @Override
    public int deleteTbQuotaByIds(Long[] ids) {
        return tbQuotaMapper.deleteTbQuotaByIds(ids);
    }

    /**
     * 删除指标配置信息
     *
     * @param id 指标配置主键
     * @return 结果
     */
    @Override
    public int deleteTbQuotaById(Long id) {
        return tbQuotaMapper.deleteTbQuotaById(id);
    }

    @Override
    public List<String> getAllSubject() {
        return tbQuotaMapper.selectTbQuotaList(null).stream().map(e -> e.getSubject()).collect(Collectors.toList());
    }

    @Override
    public DeviceInfoDTO analysis(String topic, Map<String, Object> payloadMap) {

        // 1.获取指标配置 根据主题查询指标列表
        List<TbQuota> quotaList = selectBySubject(topic);
        if (quotaList.size() == 0) {
            return null;
        }

        // 2.封装设备信息
        String snKey = quotaList.get(0).getSnKey();
        if (Strings.isNullOrEmpty(snKey)) {
            return null;
        }

        // 设备编号
        String deviceId = (String) payloadMap.get(snKey);
        if (Strings.isNullOrEmpty(deviceId)) {
            return null;
        }

        DeviceDTO deviceDTO = new DeviceDTO();
        deviceDTO.setDeviceId(deviceId);

        // 3.封装指标列表  :  循环我们根据主题名称查询得指标列表，到报文中提取，如果能够提到，进行封装
        List<QuotaDTO> quotaDTOList = Lists.newArrayList();
        for (TbQuota quota : quotaList) {
            // 指标key
            String quotaKey = quota.getValueKey();

            if (payloadMap.containsKey(quotaKey)) {
                QuotaDTO quotaDTO = new QuotaDTO();
                // 复制指标配置信息
                BeanUtils.copyProperties(quota, quotaDTO);
                quotaDTO.setQuotaName(quota.getName());

                // 指标值封装
                // 指标分为两种  1.数值  2.非数值（string boolean）
                // 1.数值   value 存储数值  stringValue :存储数值字符串
                // 2.非数值  value 0   stringValue:内容

                // 如果是非数值
                if ("String".equals(quotaDTO.getValueType()) || "Boolean".equals(quotaDTO.getValueType())) {
                    quotaDTO.setStringValue((String) payloadMap.get(quotaKey));
                    quotaDTO.setValue(0d);
                } else {// 如果是数值

                    if (payloadMap.get(quotaKey) instanceof String) {
                        quotaDTO.setValue(Double.valueOf((String) payloadMap.get(quotaKey)));
                        quotaDTO.setStringValue((String) payloadMap.get(quotaKey));
                    } else {
                        quotaDTO.setValue(Double.valueOf(payloadMap.get(quotaKey) + ""));
                        quotaDTO.setStringValue(quotaDTO.getValue() + "");
                    }
                    quotaDTO.setDeviceId(deviceId);

                }
                quotaDTOList.add(quotaDTO);
            }
        }

        // 4.封装设备+指标列表返回
        DeviceInfoDTO deviceInfoDTO = new DeviceInfoDTO();
        deviceInfoDTO.setDevice(deviceDTO);
        deviceInfoDTO.setQuotaList(quotaDTOList);

        return deviceInfoDTO;
    }

    /**
     * 查询subject相同的
     *
     * @param topic
     * @return
     */
    private List<TbQuota> selectBySubject(String topic) {
        return tbQuotaMapper.selectTbQuotaList(new TbQuota(topic));
    }


    @Override
    public void saveQuotaToTdengine(List<QuotaDTO> quotaDTOList) {
        for (QuotaDTO quotaDTO : quotaDTOList) {
            QuotaInfo quotaInfo = new QuotaInfo();
            BeanUtils.copyProperties(quotaDTO, quotaInfo);
            quotaInfo.setQuotaId(quotaDTO.getId() + "");
            tdEngineMapper.addQuotaInfo(quotaInfo);
        }
    }

    @Override
    public List<QuotaInfo> getLastQuotaList(String deviceId) {
        List<QuotaInfo> result = new ArrayList<>();
        List<Map<String, Object>> list = tdEngineMapper.getLastQuotaList(deviceId);
        // QuotaInfo quotaInfo = JSON.parseObject(JSON.toJSONString(list.get(0)), QuotaInfo.class);
        list.forEach(e -> {
            // 传到Tdengine数据库字段都变小写了，此处只能这样转
            QuotaInfo quotaInfo = e.entrySet().stream()
                    .collect(Collectors.toMap(
                            entry -> entry.getKey(),
                            entry -> entry.getValue(),
                            (existing, replacement) -> existing,
                            LinkedHashMap::new
                    ))
                    .entrySet().stream()
                    .reduce(new QuotaInfo(), (p, entry) -> {
                        switch (removeLastAndKeepContent(entry.getKey())) {
                            case "deviceid":
                                p.setDeviceId((String) entry.getValue());
                                break;
                            case "quotaid":
                                p.setQuotaId((String) entry.getValue());
                                break;
                            case "quotaname":
                                p.setQuotaName((String) entry.getValue());
                                break;
                            case "alarm":
                                p.setAlarm((String) entry.getValue());
                                break;
                            case "level":
                                p.setLevel((String) entry.getValue());
                                break;
                            case "alarmname":
                                p.setAlarmName((String) entry.getValue());
                                break;
                            case "unit":
                                p.setUnit((String) entry.getValue());
                                break;
                            case "referencevalue":
                                p.setReferenceValue((String) entry.getValue());
                                break;
                            case "numvalue":
                                p.setNumValue((Double) entry.getValue());
                                break;
                            case "stringvalue":
                                p.setStringValue((String) entry.getValue());
                                break;
                            case "ts":
                                p.setTs((Timestamp) entry.getValue());
                        }
                        return p;
                    }, (p1, p2) -> p1);
            result.add(quotaInfo);
        });
        return result;
    }

    public static String removeLastAndKeepContent(String input) {
        String pattern = "last\\((.*?)\\)";
        Pattern regex = Pattern.compile(pattern);
        Matcher matcher = regex.matcher(input);
        if (matcher.find()) {
            return matcher.group(1);
        }
        return input;
    }

}
